home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Sound / MPEGA / mpega_library / developer / demo / MPEGA_demo.c < prev    next >
C/C++ Source or Header  |  1999-09-09  |  11KB  |  348 lines

  1. /*------------------------------------------------------------------------------
  2.  
  3.     File    :   MPEGA_demo.c
  4.  
  5.     Author  :   Stéphane TAVENARD
  6.  
  7.     $VER:   MPEGA_demo.c 1.2  (05/06/1998)
  8.  
  9.     (C) Copyright 1997-1998 Stéphane TAVENARD
  10.         All Rights Reserved
  11.  
  12.     #Rev|   Date   |                      Comment
  13.     ----|----------|--------------------------------------------------------
  14.     0   |25/10/1997| Initial revision                                     ST
  15.     1   |02/05/1998| Added some time features                             ST
  16.     2   |05/06/1998| Added standard access option                         ST
  17.     3   |08/09/1999| Added verbose informations                           ST
  18.  
  19.     ------------------------------------------------------------------------
  20.  
  21.     Demo of how to use MPEGA library
  22.     Use of private bitstream access functions (access to ram buffer)
  23.  
  24. ------------------------------------------------------------------------------*/
  25.  
  26. #include <exec/exec.h>
  27. #include <clib/exec_protos.h>
  28. #include <pragmas/exec_pragmas.h>
  29. #include <dos.h>
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <time.h>
  35.  
  36. #include <libraries/mpega.h>
  37. #include <clib/mpega_protos.h>
  38. #include <pragmas/mpega_pragmas.h>
  39.  
  40. static char *Version = "$VER:MPEGA_demo 1.2 (05.06.98) (C)1997-1998 Stéphane TAVENARD";
  41.  
  42. struct Library *MPEGABase = NULL;
  43.  
  44. char *mpega_name = "mpega.library";
  45.  
  46. MPEGA_STREAM *mps = NULL;
  47.  
  48. // Ram buffer
  49. #define MPEGA_BUFFER_SIZE  (256*1024) // in bytes
  50.  
  51. BYTE   *mpega_buffer = NULL;
  52. ULONG  mpega_buffer_offset = 0;
  53. ULONG  mpega_buffer_size = 0;
  54.  
  55. static int break_cleanup( void )
  56. {
  57.    if( mps ) {
  58.       MPEGA_close( mps );
  59.       mps = NULL;
  60.    }
  61.    if( MPEGABase ) {
  62.       CloseLibrary( MPEGABase );
  63.       MPEGABase = NULL;
  64.    }
  65.    return 1;
  66. }
  67.  
  68. static void exit_cleanup( void )
  69. {
  70.    (void)break_cleanup();
  71. }
  72.  
  73. // Here start our own bitstream access routines
  74.  
  75. static ULONG __saveds __asm def_baccess( register __a0 struct Hook  *hook,
  76.                                          register __a2 APTR          handle,
  77.                                          register __a1 MPEGA_ACCESS *access ) {
  78. /*----------------------------------------------------------------------------
  79. */
  80.  
  81.    switch( access->func ) {
  82.  
  83.       case MPEGA_BSFUNC_OPEN:
  84.          // We don't really need stream_name
  85.          // buffer_size indicate the following read access size
  86.  
  87. printf( "bitstream open: filename='%s'\n", access->data.open.stream_name );
  88. printf( "bitstream open: buffer_size=%d\n", access->data.open.buffer_size );
  89.  
  90.          // Some open errors...
  91.          if( !mpega_buffer ) return NULL;
  92.  
  93.          // initialize some variables
  94.          mpega_buffer_offset = 0;
  95.  
  96.          // We know total size, we can set it
  97.          access->data.open.stream_size = mpega_buffer_size;
  98.  
  99.          // Just return a dummy handle (not NULL)
  100.          return 1;
  101.  
  102.       case MPEGA_BSFUNC_CLOSE:
  103.          if( handle ) {
  104.             // Clean up
  105. printf( "bitstream close\n" );
  106.          }
  107.          break;
  108.       case MPEGA_BSFUNC_READ: {
  109.          LONG read_size;
  110.  
  111.          if( !handle ) return 0; // Check valid handle
  112.  
  113.          read_size = mpega_buffer_size - mpega_buffer_offset;
  114.          if( read_size > access->data.read.num_bytes ) read_size = access->data.read.num_bytes;
  115.  
  116.          if( read_size > 0 ) {
  117.             if( !access->data.read.buffer ) return 0;
  118.             // Fill buffer with our MPEG audio data
  119.             memcpy( access->data.read.buffer, &mpega_buffer[ mpega_buffer_offset ], read_size );
  120.             mpega_buffer_offset += read_size;
  121.          }
  122.          else {
  123.             read_size = 0; // End of stream
  124.          }
  125. //printf( "bitstream read: requested %d bytes, read %d\n", access->data.read.num_bytes, read_size );
  126.  
  127.          return (ULONG)read_size;
  128.       }
  129.       case MPEGA_BSFUNC_SEEK:
  130.          if( !handle ) return 0;
  131.  
  132. printf( "bitstream seek: pos = %d\n", access->data.seek.abs_byte_seek_pos );
  133.          if( access->data.seek.abs_byte_seek_pos <= 0 ) mpega_buffer_offset = 0;
  134.          else if( access->data.seek.abs_byte_seek_pos >= mpega_buffer_size ) return 1;
  135.          else mpega_buffer_offset = access->data.seek.abs_byte_seek_pos;
  136.          return 0;
  137.    }
  138.    return 0;
  139. }
  140.  
  141. static struct Hook def_bsaccess_hook = {
  142.    { NULL, NULL }, def_baccess, NULL, NULL
  143. };
  144.  
  145. int output_pcm( WORD channels, WORD *pcm[ 2 ], LONG count, FILE *out_file )
  146. /*---------------------------------------------------------------------------
  147.    Ouput the current decoded PCM to a file
  148.    Return 0 if Ok
  149. */
  150. {
  151. #define PCM_BUFFER_SIZE (MPEGA_MAX_CHANNELS*MPEGA_PCM_SIZE)
  152.    static WORD *pcm_buffer = NULL;
  153.    if( !out_file ) return -1;
  154.  
  155.    if( !pcm_buffer ) {
  156.       pcm_buffer = (WORD *)malloc( PCM_BUFFER_SIZE * sizeof(WORD) );
  157.       if( !pcm_buffer ) return -1;
  158.    }
  159.    if( channels == 2 ) {
  160.       register WORD *pcm0, *pcm1, *pcmLR;
  161.       register LONG i;
  162.  
  163.       pcm0 = pcm[ 0 ];
  164.       pcm1 = pcm[ 1 ];
  165.       pcmLR = pcm_buffer;
  166.       i = count;
  167.       while( i-- ) {
  168.          *pcmLR++ = *pcm0++;
  169.          *pcmLR++ = *pcm1++;
  170.       }
  171.       fwrite( pcm_buffer, 4, count, out_file );
  172.    }
  173.    else {
  174.       fwrite( pcm[ 0 ], 2, count, out_file );
  175.    }
  176.  
  177.    return 0;
  178.  
  179. } /* output_pcm */
  180.  
  181. int main( int argc, char **argv )
  182. {
  183.    char *in_filename;
  184.    FILE *in_file;
  185.    int frame = 0;
  186.    char *out_filename = NULL;
  187.    FILE *out_file = NULL;
  188.    WORD i;
  189.    LONG pcm_count, total_pcm = 0;
  190.    LONG index;
  191.    WORD *pcm[ MPEGA_MAX_CHANNELS ];
  192.    clock_t clk; // #1
  193.    double secs; // #1
  194.    int custom = 1; // #2
  195.    long br_sum = 0;
  196. //ULONG ms;
  197.  
  198.    static const char *layer_name[] = { "?", "I", "II", "III" };
  199.    static const char *mode_name[] = { "stereo", "j-stereo", "dual", "mono" };
  200.  
  201.    MPEGA_CTRL mpa_ctrl = {
  202.       NULL,    // Bitstream access is default file I/O
  203.       // Layers I & II settings (mono, stereo)
  204.       { FALSE, { 1, 2, 48000 }, { 1, 2, 48000 } },
  205.       // Layer III settings (mono, stereo)
  206.       { FALSE, { 1, 2, 48000 }, { 1, 2, 48000 } },
  207.       0,           // Don't check mpeg validity at start (needed for mux stream)
  208.       32678        // Stream Buffer size
  209.    };
  210.  
  211.  
  212. //printf( "MPEGA_demo: sizeof( MPEGA_CTRL ) = %d\n", sizeof( MPEGA_CTRL ) );
  213. //printf( "MPEGA_demo: sizeof( MPEGA_STREAM ) = %d\n", sizeof( MPEGA_STREAM ) );
  214.  
  215.    onbreak( break_cleanup );
  216.    atexit( exit_cleanup );
  217.  
  218.    if( argc <= 1 ) {
  219.       fprintf( stderr, "%s\n", &Version[ 5 ] );
  220.       fprintf( stderr, "Usage %s <input mpeg audio file> [<output pcm file>] [-d]\n", argv[ 0 ] );
  221.       fprintf( stderr, "option: -d = default file access (custom bitstream access otherwise)\n" ); // #2
  222.       fprintf( stderr, "This is a demo of how to use mpega.library\n" );
  223.       fprintf( stderr, "This also show how to use custom bitstream access\n" );
  224.       exit( 0 );
  225.    }
  226.  
  227.    MPEGABase = OpenLibrary( mpega_name, 0L );
  228.    if( !MPEGABase ) {
  229.       printf( "Unable to open '%s'\n", mpega_name );
  230.       exit( 0 );
  231.    }
  232.  
  233.    in_filename = argv[ 1 ];
  234.  
  235.    for( i=2; i<argc; i++ ) { // #2
  236.       if( strcmp( argv[ i ], "-d" ) == 0 ) {
  237.          custom = 0;
  238.       }
  239.       else {
  240.          out_filename = argv[ i ];
  241.       }
  242.    }
  243.  
  244.    for( i=0; i<MPEGA_MAX_CHANNELS; i++ ) {
  245.       pcm[ i ] = malloc( MPEGA_PCM_SIZE * sizeof( WORD ) );
  246.       if( !pcm[ i ] ) {
  247.          fprintf( stderr, "Can't allocate PCM buffers\n" );
  248.          exit( 0 );
  249.       }
  250.    }
  251.  
  252.    // Open the output file
  253.    if( out_filename ) {
  254.       out_file = fopen( out_filename, "wb" );
  255.       if( !out_file ) {
  256.          fprintf( stderr, "Can't create output file '%s'\n", out_filename );
  257.          exit( 0 );
  258.       }
  259.    }
  260.  
  261.    if( custom ) { // #2 (custom bitstream access)
  262.       printf( "Custom bitstream access used\n" ); // #2
  263.       mpega_buffer = (BYTE *)malloc( MPEGA_BUFFER_SIZE );
  264.       if( !mpega_buffer ) {
  265.          fprintf( stderr, "Can't allocate MPEG buffer\n" );
  266.          exit( 0 );
  267.       }
  268.  
  269.  
  270.       // Load the stream into a ram buffer
  271.       in_file = fopen( in_filename, "rb" );
  272.       if( !in_file ) {
  273.          fprintf( stderr, "Unable to open file '%s'\n", in_filename );
  274.          exit( 0 );
  275.       }
  276.       mpega_buffer_size = fread( mpega_buffer, 1, MPEGA_BUFFER_SIZE, in_file );
  277.       fclose( in_file );
  278.       printf( "Read %d bytes from file '%s'\n", mpega_buffer_size, in_filename );
  279.  
  280.       // #1 Begin
  281.       printf( "Test if MPEG Audio sync inside...\n" );
  282.       index = MPEGA_find_sync( mpega_buffer, MPEGA_BUFFER_SIZE );
  283.       if( index >= 0 ) {
  284.          printf( "Ok, found MPEG Audio sync at position %d\n", index );
  285.       }
  286.       else {
  287.          printf( "* Error %d *\n", index );
  288.       }
  289.       // #1 End
  290.  
  291.       // Set our bitstream access routines and open the stream
  292.       mpa_ctrl.bs_access = &def_bsaccess_hook;
  293.    }
  294.    else {
  295.       printf( "Default bitstream access used\n" ); // #2
  296. printf( "Buffer size = %d\n", mpa_ctrl.stream_buffer_size );
  297.    }
  298.  
  299.    mps = MPEGA_open( in_filename, &mpa_ctrl );
  300.    if( !mps ) {
  301.       printf( "Unable to find MPEG Audio stream in file '%s'\n", in_filename );
  302.       exit( 0 );
  303.    }
  304.  
  305.    printf( "\n" );
  306.    printf( "MPEG norm %d Layer %s\n", mps->norm, layer_name[ mps->layer ] );
  307.    printf( "Bitrate: %d kbps\n", mps->bitrate );
  308.    printf( "Frequency: %d Hz\n", mps->frequency );
  309.    printf( "Mode: %d (%s)\n", mps->mode, mode_name[ mps->mode ] );
  310.    printf( "Stream duration: %ld ms\n", mps->ms_duration );
  311.    printf( "\n" );
  312.    printf( "Output decoding parameters\n" );
  313.    printf( "Channels: %d\n", mps->dec_channels );
  314.    printf( "Quality: %d\n", mps->dec_quality );
  315.    printf( "Frequency: %d Hz\n", mps->dec_frequency );
  316.    printf( "\n" );
  317.  
  318.    clk = clock(); // #1
  319.    while( (pcm_count = MPEGA_decode_frame( mps, pcm )) >= 0 ) {
  320. //MPEGA_time( mps, &ms );
  321.  
  322.       br_sum += mps->bitrate; // #3
  323.       total_pcm += pcm_count;
  324.       if( out_file ) output_pcm( mps->dec_channels, pcm, pcm_count, out_file );
  325.       frame++;
  326.       if( (frame & 31) == 0 ) {
  327.          fprintf( stderr, "{%04d} %7.3fkbps\r", frame, (double)br_sum / (double)(frame+1) ); fflush( stderr );
  328.       }
  329.    }
  330.    clk = clock() - clk; // #1
  331.    secs = (double)clk / (double)CLK_TCK; // #1
  332.    printf( "\ntime used = %7.3f secs\n", secs ); // #1
  333.    printf( "%ld samples / sec\n", (int)((double)total_pcm / secs) );
  334.    printf( "%7.3f % CPU used on real time\n", ((double)mps->frequency * 100) / ((double)total_pcm / secs) );
  335.  
  336.    fprintf( stderr, "\n" );
  337.  
  338.    fprintf( stderr, "last pcm_count = %d\n", pcm_count );
  339.    fprintf( stderr, "total_pcm = %d\n", total_pcm );
  340.  
  341.    MPEGA_close( mps );
  342.    mps = NULL;
  343.    CloseLibrary( MPEGABase );
  344.    MPEGABase = NULL;
  345.  
  346. }
  347.  
  348.